/*
* This file is the main code of Texdi
* Copyright (C) <2017>  <alkeon> [alkeon@autistici.org]
*
* Texdi is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Texdi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Texdi.  If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include "tedi2html.h"
#include "exception.h"
using namespace std;
/*
 * This function converts a string with Tedi format and return 
 * a string with HTML format.
 * Header and footer are by default void.
 */
string tedi2html(string text, string header, string footer){
	stringstream index(text);
	string line;
	string return_text = header;
	int control=0;
	int open_brackets=0;
	while(getline(index,line)){
		if(line[0]!='<'){
			size_t hash=line.find('#');
			if(hash!=string::npos){
				line=titles_ht(line);
				return_text+=line+"\n";
			}else{
				size_t ul=line.find("__");
				if(ul!=string::npos)
					return_text+="<ul>\n";
					
				size_t li=line.find("--");
				if(li!=string::npos){
					  line=line.erase(li,2);
					  line=line.insert(li,"<li>");
				}
				size_t ulf=line.find(",,");
				if(ulf!=string::npos)
					return_text+="</ul>\n";
				
				size_t comi=line.find("\"");
				if(comi!=string::npos){
					if(line[line.size()-1]=='"')
						line=line.substr(1,line.size()-2);
					else
						throw Invalid("Missing end quotes.",line);
				}else{
					int etiq=main_tag(line);
					while(etiq!=-1){
						if(etiq==2){
							size_t lla2=line.find("}");
							if(lla2==string::npos){
								++open_brackets;
								line=incomplete_blocks_ht(line);
							}else
								line=blocks_ht(line);
						}else{
							if(etiq==0)
								line=images_ht(line);
							else
								line=links_ht(line);
						}
						etiq=main_tag(line);

					}
					size_t lla2=line.find("}");
					if(lla2!=string::npos){
						if(open_brackets==0)
							throw Invalid("Missing '{' in block tag.",line);
						--open_brackets;
						line=line.erase(lla2,1);
						line=line.insert(lla2,"</div>");
					}
					
					
					size_t hor=line.find("|");
					if(control==0){
						size_t hor1=line.rfind("|");
						if(hor!=string::npos && hor!=hor1){
							return_text+="<table>\n<tr>\n";
							table_ht(line,return_text);
							control=1;
						}
					}else{
						if(hor==string::npos){
							return_text+="</table>\n";
							control=0;
						}else{
							return_text+="<tr>\n";
							table_ht(line,return_text);
						}
					}
					size_t minor=line.rfind(" ");
					if(minor==line.size()-1 && line.size()>1){
						return_text+=line+ "<p>\n";
					}else{
						if(ulf==string::npos && ul==string::npos && hash==string::npos){
							return_text+=line+ "\n";
						}
					}
				}
			}
		}else{
			if(line[1]!='!'){
				if(line[1]=='>'){
					line=line.erase(0,2);
					return_text+=line+ "\n";
				}else{
					line=line.erase(0,1);
					return_text+=line+ "<p>\n";
				}
			}
		}
	}
	if(open_brackets>0)
		throw Invalid("Missing '}' in document.","End of file");
	return_text+=footer;
	return return_text;
}
/*
 * Detects next tag
 * Returns 
 * 0: images
 * 1: links
 * 2: blocks
 * -1: No tag
 */
int main_tag(string line){
	int etiq=-1;
	size_t cont=line.size();
	size_t lla=line.find("{");
	size_t paren=line.find("([");
	size_t corch=line.find("[(");
	if(lla!= string::npos && lla<cont){
		etiq=2;
		cont=lla;
	}
	if(corch != string::npos && corch<cont){
		cont=corch;
		etiq=1;
	}
	if(paren != string::npos && paren<cont)
		etiq=0;
	return etiq;
}
/*
 * Convert Tedi table to a HTML link (line by line)
 *
 */
void table_ht(string& line,string& return_text){
	return_text+="<tr>\n";
	size_t hor=line.find("|");
	if(hor!=string::npos){
		++hor;
		line=line.substr(hor,line.size()-1);
		hor=line.find("|");
		if(hor!=string::npos){
			int tam=line.size()-1;
			while(hor!=string::npos && line[tam]=='|'){
				string elemento;
				elemento=line.substr(0,hor);
				return_text+="<td>"+elemento+"</td>\n";
				++hor;
				line=line.substr(hor,line.size()-1);
				hor=line.find("|");
				tam=line.size()-1;
			}
			return_text+="</tr>\n";
		}else{
			throw Invalid("Expected '|' in table", line);
		}
	}else{
		throw Invalid("Expected '|' in table", line);
	}
}
/*
 * Convert Tedi link to a HTML link
 *
 */
string links_ht(string line){
	size_t start_tag=line.find("[(");
	string aux="<a href=\"";
	if(start_tag!= string::npos){
		line=line.erase(start_tag,2);
		line=line.insert(start_tag,aux);
		size_t par1=line.find(")");
		if(par1!=string::npos){
			line=line.erase(par1,1);
			aux="\">";
			line=line.insert(par1,aux);
			size_t brack=line.rfind("]");
			if(brack!=string::npos){
				line=line.erase(brack,1);
				aux="</a>";
				line=line.insert(brack,aux);
			}else
				throw Invalid("Missing ']' in link tag.",line);
		}else
			throw Invalid("Missing ')' in link tag.",line);
	}else
		throw Invalid("Missing link tag.",line);

	return line;
}
/*
 * Deletes parentheses and adds HTML text of a image.
 *
 */
string images_ht(string line){
	size_t start_tag=line.find("([");
	string aux="<img alt=\"";
	if(start_tag!= string::npos){
		line=line.erase(start_tag,2);
		line=line.insert(start_tag,aux);
		size_t par1=line.find("]");
		if(par1!=string::npos){
			line=line.erase(par1,1);
			aux="\" src=\"";
			line=line.insert(par1,aux);
			size_t brack=line.rfind(")");
			if(brack!=string::npos){
				line=line.erase(brack,1);
				aux="\">";
				line=line.insert(brack,aux);
			}else
				throw Invalid("Missing ')' in images tag.",line);
		}else
			throw Invalid("Missing ']' in images tag.",line);
	}else
		throw Invalid("Missing images tag.",line);

	return line;
}
/*
 * Deletes hashes and adds HTML text of a title.
 *
 */
string titles_ht(string line){
	size_t exa1=line.find("#");
	int ti=0;
	while(exa1!=string::npos && line[exa1]=='#'){
		++exa1;
		line=line.substr(exa1,line.size()-1);
		exa1=line.find("#");
		++ti;
	}
	if(ti>6)
		ti=6;
	string ti2=to_string(ti);
	line="<h"+ti2+">"+line+"</h"+ti2+">";
	return line;
}
/*
 * Deletes brackes and parentheses. Adds HTML text 
 * of a <div> container.
 *
 */
string blocks_ht(string line){
	size_t lla1=line.find("{(");
	if(lla1!=string::npos){
		line=line.erase(lla1,2);
		string nop="<div class=\"";
		line=line.insert(lla1,nop);
		lla1=line.find(")");
		if(lla1!=string::npos){
			nop="\">";
			line=line.erase(lla1,1);
			line=line.insert(lla1,nop);
			lla1=line.rfind("}");
			if(lla1!=string::npos){
				nop="</div>";
				line=line.erase(lla1,1);
				line=line.insert(lla1,nop);
			}else
				throw Invalid("Missing '}' in block tag.",line);
		}else
			throw Invalid("Missing ')' in block tag.",line);
	}else
		throw Invalid("Missing block tag.",line);
	return line;
}
/*
 * Deletes brackes and parentheses. Adds HTML text 
 * of a <div> container.
 *
 */
string incomplete_blocks_ht(string line){
	size_t key1=line.find("{(");
	if(key1!= string::npos){

		line.erase(key1,2);
		line.insert(key1,"<div class=\"");
		
		size_t par=line.find(")");
		if(par!=string::npos){
			line.erase(par,1);
			line.insert(par,"\">");
			size_t key2=line.find("}");
			if(key2!=string::npos)
				throw Invalid("Unexpected '}' in incomplete block tag.",line);
		}else
			throw Invalid("Missing ')' in block tag.",line);
	}else
		throw Invalid("Missing block tag.",line);
	return line;
}
